package iks.net
{
	import flash.errors.*;
	import flash.events.*;
	import flash.net.*;
	import flash.utils.*;
	import iks.event.*;
	import iks.net.codec.*;
	import iks.utils.*;
	
	/**
	 * 套接字通道
	 * @author Kaka
	 */
	public final class SocketChannel extends EventDispatcher
	{
		/// 构造函数
		public function SocketChannel() 
		{
			super();
			init();
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 公共域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/**
		 * 将套接字连接到指定的主机和端口
		 * @param	host 一个完全限定的 DNS 域名，或 111.222.333.444 形式的 IP 地址
		 * @param	port 用于建立连接的目标主机上的 TCP 端口号
		 */
		public function connect(host : String, port : int) : void
		{
			m_remoteAddress = host;
			m_remotePort = port;
			m_socket.connect(host, port);
		}
		
		/// 关闭套接字连接
		public function close() : void
		{
			m_socket.close();
			m_socket.removeEventListener(Event.CLOSE, onClose);
			m_socket.removeEventListener(Event.CONNECT, onConnected);
			m_socket.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
			m_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			m_socket.removeEventListener(ProgressEvent.SOCKET_DATA, onReceiveData);
		}
		
		/**
		 * 添加编码器
		 * @param	encode 编码器
		 */
		public function addEncode(encode : IChannelEncode) : void
		{
			m_encodes.push(encode);
		}
		
		/**
		 * 添加解码器
		 * @param	decode 解码器
		 */
		public function addDecode(decode : IChannelDecode) : void
		{
			m_decodes.push(decode);
		}
		
		/**
		 * 发送数据到已连接的主机, 此方法直接调用flush, 不需要再显示调用flush
		 * @param	buffer 发送的字节序列
		 */
		public function write(buffer : ByteArray) : void
		{
			var length : int = m_encodes.length;
			for (var i : int = length - 1; i >= 0; --i)
				buffer = m_encodes[i].encodeData(buffer);
				
			m_socket.writeBytes(buffer);
			m_socket.flush();
		}
		
		/**
		 * 指示此 Socket 对象目前是否已连接。 如果该套接字当前已连接，则对此属性的调用将返回值 true，否则将返回 false
		 */
		public function get connected() : Boolean
		{
			return m_socket.connected;
		}
		
		/**
		 * 指示建立连接时需等待的毫秒数
		 * 如果在指定时间内未成功建立连接，则连接失败。默认值是 20,000（20 秒）
		 */
		public function set timeout(value : uint) : void
		{
			m_socket.timeout = value;
		}
		
		public function get timeout() : uint
		{
			return m_socket.timeout;
		}
		
		/**
		 * 远程连接的地址
		 */
		public function get remoteAddress() : String
		{
			return m_remoteAddress;
		}
		
		/**
		 * 远程连接的端口
		 */
		public function get remotePort() : int
		{
			return m_remotePort;
		}
		
///////////////////////////////////////////////////////////////////////////////////////////////////
// 私有域
///////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// 初始化
		private function init() : void
		{
			m_socket = new Socket();
			m_socket.addEventListener(Event.CLOSE, onClose);
			m_socket.addEventListener(Event.CONNECT, onConnected);
			m_socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
			m_socket.addEventListener(ProgressEvent.SOCKET_DATA, onReceiveData);
			m_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
			
			m_encodes = new Vector.<IChannelEncode>();
			m_decodes = new Vector.<IChannelDecode>();
		}
		
		/// 当服务器关闭套接字连接
		private function onClose(evt : Event) : void
		{
			this.dispatchEvent(evt);
		}
		
		/// 当连接上服务器
		private function onConnected(evt : Event) : void
		{
			this.dispatchEvent(evt);
		}
		
		/// 当发送或者装载的时候产生一个输入输出错误
		private function onIOError(evt : IOErrorEvent) : void
		{
			if (!this.hasEventListener(IOErrorEvent.IO_ERROR))
				throw new IOError(evt.text);
			
			this.dispatchEvent(evt);
		}
		
		/**
		 * Dispatched if a call to Socket.connect() attempts to connect to a
		 * server prohibited by the caller's security sandbox or to a port
		 * lower than 1024 and no socket policy file exists to permit such a connection.
		 * @param	evt
		 */
		private function onSecurityError(evt : SecurityErrorEvent) : void
		{
			if (!this.hasEventListener(SecurityErrorEvent.SECURITY_ERROR))
				throw new SecurityError(evt.text);
			
			this.dispatchEvent(evt);
		}
		
		/// 接收到套接字数据
		private function onReceiveData(evt : ProgressEvent) : void
		{
			var message : ByteArray = new ByteArray();
			var socket : Socket = Socket(evt.target);
			socket.readBytes(message);
			
			while (message.bytesAvailable)
			{
				// 分析每个数据帧
				var bytes : ByteArray = message;
				var length : int = m_decodes.length;
				for (var i : int = 0; i < length; ++i)
				{
					bytes = m_decodes[i].decodeData(bytes);
					
					if (bytes == null)
						break;
				}
				
				// 当接收到一个数据帧的时候, 则派发接收数据事件
				if (bytes != null)
					this.dispatchEvent(new SocketChannelEvent(SocketChannelEvent.RECEIVEDATA, bytes));
			}
		}
		
		private var m_socket : Socket = null;
		private var m_encodes : Vector.<IChannelEncode> = null;
		private var m_decodes : Vector.<IChannelDecode> = null;
		private var m_remoteAddress : String = null;
		private var m_remotePort : int = 0;
	}

}